package creatingPattern.builder;

/**
 * 建造者模式示例：装修房子
 * 设计意图：将复杂对象的构建与表示分离，使同样的构建过程可以创建不同的表示
 * 使用场景：当需要创建复杂对象时，建造者模式可简化对象创建过程
 */
public class BuilderClient {
    /**
     * 主方法：演示建造者模式
     * 设计意图：通过XML配置动态创建建造者和产品
     * 使用场景：当需要根据配置创建不同产品时，调用此方法
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        try {
            Decorator d;
            d = (Decorator) ReadXML.getObject();
            ProjectManager m = new ProjectManager(d);
            Parlour p = m.decorate();
            p.show();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

/**
 * 产品：客厅
 * 设计意图：定义产品的组成部分
 * 使用场景：当需要创建复杂对象时，产品类可定义对象的组成部分
 */
class Parlour {
    /**
     * 墙
     * 设计意图：存储墙的信息
     * 使用场景：当需要展示墙的信息时，使用此字段
     */
    private String wall;

    /**
     * 电视
     * 设计意图：存储电视的信息
     * 使用场景：当需要展示电视的信息时，使用此字段
     */
    private String TV;

    /**
     * 沙发
     * 设计意图：存储沙发的信息
     * 使用场景：当需要展示沙发的信息时，使用此字段
     */
    private String sofa;

    /**
     * 设置墙
     * 设计意图：修改墙的信息
     * 使用场景：当需要修改墙的信息时，调用此方法
     * @param wall 墙的信息
     */
    public void setWall(String wall) {
        this.wall = wall;
    }

    /**
     * 设置电视
     * 设计意图：修改电视的信息
     * 使用场景：当需要修改电视的信息时，调用此方法
     * @param TV 电视的信息
     */
    public void setTV(String TV) {
        this.TV = TV;
    }

    /**
     * 设置沙发
     * 设计意图：修改沙发的信息
     * 使用场景：当需要修改沙发的信息时，调用此方法
     * @param sofa 沙发的信息
     */
    public void setSofa(String sofa) {
        this.sofa = sofa;
    }

    /**
     * 显示客厅
     * 设计意图：展示客厅信息
     * 使用场景：当需要展示客厅信息时，调用此方法
     */
    public void show() {
        System.out.println("建造者模式测试结果：");
        String parlour = wall + TV + sofa;
        System.out.println(parlour);
    }
}

/**
 * 抽象建造者：装修工人
 * 设计意图：定义创建产品的抽象方法
 * 使用场景：当需要创建复杂对象时，抽象建造者类可定义创建产品的抽象方法
 */
abstract class Decorator {
    /**
     * 产品对象
     * 设计意图：存储产品对象
     * 使用场景：当需要创建产品对象时，使用此字段
     */
    protected Parlour product = new Parlour();

    /**
     * 建造墙
     * 设计意图：定义建造墙的抽象方法
     * 使用场景：当需要建造墙时，调用此方法
     */
    public abstract void buildWall();

    /**
     * 建造电视
     * 设计意图：定义建造电视的抽象方法
     * 使用场景：当需要建造电视时，调用此方法
     */
    public abstract void buildTV();

    /**
     * 建造沙发
     * 设计意图：定义建造沙发的抽象方法
     * 使用场景：当需要建造沙发时，调用此方法
     */
    public abstract void buildSofa();

    /**
     * 获取产品
     * 设计意图：返回产品对象
     * 使用场景：当需要获取产品对象时，调用此方法
     * @return 返回产品对象
     */
    public Parlour getResult() {
        return product;
    }
}

/**
 * 具体建造者：具体装修工人1
 * 设计意图：实现抽象建造者类，提供具体产品创建方法
 * 使用场景：当需要创建具体产品时，具体建造者类可提供具体实现
 */
class ConcreteDecorator1 extends Decorator {
    /**
     * 建造墙
     * 设计意图：实现建造墙的抽象方法
     * 使用场景：当需要建造墙时，调用此方法
     */
    public void buildWall() {
        product.setWall("w1");
    }

    /**
     * 建造电视
     * 设计意图：实现建造电视的抽象方法
     * 使用场景：当需要建造电视时，调用此方法
     */
    public void buildTV() {
        product.setTV("TV1");
    }

    /**
     * 建造沙发
     * 设计意图：实现建造沙发的抽象方法
     * 使用场景：当需要建造沙发时，调用此方法
     */
    public void buildSofa() {
        product.setSofa("sf1");
    }
}

/**
 * 具体建造者：具体装修工人2
 * 设计意图：实现抽象建造者类，提供具体产品创建方法
 * 使用场景：当需要创建具体产品时，具体建造者类可提供具体实现
 */
class ConcreteDecorator2 extends Decorator {
    /**
     * 建造墙
     * 设计意图：实现建造墙的抽象方法
     * 使用场景：当需要建造墙时，调用此方法
     */
    public void buildWall() {
        product.setWall("w2");
    }

    /**
     * 建造电视
     * 设计意图：实现建造电视的抽象方法
     * 使用场景：当需要建造电视时，调用此方法
     */
    public void buildTV() {
        product.setTV("TV2");
    }

    /**
     * 建造沙发
     * 设计意图：实现建造沙发的抽象方法
     * 使用场景：当需要建造沙发时，调用此方法
     */
    public void buildSofa() {
        product.setSofa("sf2");
    }
}

/**
 * 指挥者：项目经理
 * 设计意图：调用建造者中的方法完成复杂对象的创建
 * 使用场景：当需要创建复杂对象时，指挥者类可调用建造者中的方法完成对象创建
 */
class ProjectManager {
    /**
     * 建造者
     * 设计意图：存储建造者对象
     * 使用场景：当需要创建产品对象时，使用此字段
     */
    private Decorator builder;

    /**
     * 构造函数
     * 设计意图：初始化建造者对象
     * 使用场景：当需要创建指挥者对象时，调用此构造函数
     * @param builder 建造者对象
     */
    public ProjectManager(Decorator builder) {
        this.builder = builder;
    }

    /**
     * 装修
     * 设计意图：调用建造者中的方法完成复杂对象的创建
     * 使用场景：当需要创建复杂对象时，调用此方法
     * @return 返回产品对象
     */
    public Parlour decorate() {
        builder.buildWall();
        builder.buildTV();
        builder.buildSofa();
        return builder.getResult();
    }
}